🧬 얕은 복사 & 깊은 복사
객체를 복사한다고 해서 항상 완전히 새로운 객체가 만들어지는 것은 아닙니다.
JavaScript에서 객체 복사는 얕은 복사(Shadow Copy) 와 깊은 복사(Depp Copy) 로 나뉘며,
이 차이를 이해하지 못하면 의도치 않은 상태 변경 버그가 발생할 수 있습니다.
1️⃣ 값 복사 vs 참조 복사
JavaScript의 데이터 타입은 크게 두 가지로 나뉩니다.
- 원시 타입 (Primitive) → 값 복사
- 참조 타입 (Object) → 참조(주소) 복사
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
하지만 객체는 다릅니다.
const obj1 = { x: 1 };
const obj2 = obj1;
obj2.x = 2;
console.log(obj1.x); // 2
👉 객체 변수에는 값이 아니라 참조(메모리 주소) 가 저장됩니다.
2️⃣ 얕은 복사 (Shallow Copy)
객체의 1단계 프로퍼티만 복사하고,
중첩된 객체는 같은 참조를 공유하는 복사 방식
🔹 대표적인 얕은 복사 방법
Object.assign({}, obj)
{ ...obj }
Array.prototype.slice();
🧐 예제
const original = {
name: "Kim",
info: {
age: 20,
},
};
const copy = { ...original };
copy.info.age = 30;
console.log(original.info.age); // 30 ❗
📌 original과 copy는 서로 다른 객체지만
info는 같은 객체를 참조하고 있습니다.
3️⃣ 얕은 복사의 특징과 한계
✅ 장점
- 빠름
- 문법이 간결
- 1단계 구조에서는 안전
❌ 한계
- 중첩 객체에서 참조 공유 문제 발생
- 불변성 보장이 아님
👉 “복사한 줄 알았는데 원본이 바뀌는” 상황의 원인
4️⃣ 깊은 복사 (Deep Copy)
객체 내부의 모든 중첩 구조까지
완전히 새로운 참조로 복사하는 방식
🔹 JSON.parse(JSON.stringify())
const deepCopy = JSON.parse(JSON.stringify(original));
⚠️ 단점
undefined,Symbol,Funtion제거Date,Map,Set손실- 순환 참조 ❌
🔹 재귀를 이용한 직접 구현
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") return obj;
const result = Array.isArray(obj) ? [] : {};
for (const key in obj) {
result[key] = deepCopy(obj[key]);
}
return result;
}
🔹 structuredClone (최신 ⭐)
const copy = structuredClone(original);
- 브라우저 / Node 최신 환경 지원
- 순환 참조 가능
- 대부분의 내장 객체 지원
5️⃣ 얕은 복사 vs 깊은 복사 비교
| 구분 | 얕은 복사 | 깊은 복사 |
|---|---|---|
| 1단계 프로퍼티 | 복사 | 복사 |
| 중첩 객체 | 참조 공유 | 완전 복사 |
| 성능 | 빠름 | 느릴 수 있음 |
| 안전성 | 낮음 | 높음 |
6️⃣ Object.freeze와의 관계
Object.freeze(obj);
- 객체를 변경 불가 상태로 만듦
- ❗ 중첩 객체는 여전히 변경 가능
const obj = Object.freeze({
inner: { x: 1 }
});
obj.inner.x = 2; // 가능
📌 freeze는 얕은 불변성만 제공합니다.
✍️ 한 줄 정리
JavaScript에서 객체 복사는 기본적으로 얕은 복사이며,
중첩 구조까지 안전하게 다루려면 깊은 복사 전략을 명확히 선택해야 합니다.